package com.zjgeport.zjgdanger.widget;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ref.SoftReference;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.StatFs;
import android.util.Log;

import com.zjgeport.zjgdanger.common.ParamCommon;

public class AsyncLoaderViewPageImage
{
	private static String TAG = "AsyncLoaderViewPageImage";
	private static HashMap<String, SoftReference<Bitmap>> bitmapCache;

	private static final String WHOLESALE_CONV = ParamCommon.APP_FILE_CACHE;
	private static final int mTimeDiff = 5 * 24 * 60 * 60 * 1000;
	private static final int FREE_SD_SPACE_NEEDED_TO_CACHE = 50;
	private static final int CACHE_SIZE = 1024 * 1024;

	public AsyncLoaderViewPageImage()
	{
		if (bitmapCache == null)
		{
			bitmapCache = new HashMap<String, SoftReference<Bitmap>>();
		}
	}

	/**
	 * 先从软引用中获取图片未取到则从SDCard上取
	 * 
	 * @param url
	 * @param imageCallback
	 * @return
	 */
	public Bitmap loadBitmap(final String url, final ImageADCallback imageCallback)
	{
		Bitmap bitmap;
		/**
		 * 从软引用中获取图片
		 */
		if (bitmapCache.containsKey(url))
		{
			SoftReference<Bitmap> softReference = bitmapCache.get(url);
			bitmap = softReference.get();
			if (bitmap != null)
			{
				System.out.println("成功从软引用中获取图片：" + url);
				return bitmap;
			}
		}
		/**
		 * 从SD卡中获取图片
		 */
		bitmap = getBitmapFromSD(url);
		if (bitmap != null)
		{
			/**
			 * 取到后放入软引用中
			 */
			System.out.println("将图片：" + url + "放入软引用中");
			bitmapCache.put(url, new SoftReference<Bitmap>(bitmap));
			return bitmap;
		}

		final Handler handler = new Handler()
		{
			@Override
			public void handleMessage(Message msg)
			{
				imageCallback.imageLoaded((Bitmap) msg.obj, url);
			}
		};
		/**
		 * 都未取到则开启线程下载图片
		 */
		new Thread()
		{
			@Override
			public void run()
			{
				try
				{
					Bitmap bitmap = DownLoadBitmap(url);
					if (bitmap != null)
					{
						/**
						 * 下载完成后入软引用中
						 */
						System.out.println("将图片：" + url + "放入软引用中");
						bitmapCache.put(url, new SoftReference<Bitmap>(bitmap));
						/**
						 * 将图片保存到本地
						 */
						saveBmpToSd(bitmap, url);
						handler.obtainMessage(0, bitmap).sendToTarget();
					}
				}
				catch (OutOfMemoryError error)
				{
					Log.i(TAG, error.toString());
					System.gc();
				}
				catch (Exception e)
				{
					e.printStackTrace();
				}
			}
		}.start();
		return null;
	}

	public interface ImageADCallback
	{
		public void imageLoaded(Bitmap imageBitmap, String imageUrl);
	}

	/**
	 * 线程中调用此方法加载图片
	 * 
	 * @param path
	 * @return
	 * @throws IOException
	 */
	@SuppressWarnings("static-access")
	public static Bitmap DownLoadBitmap(String path)
	{
		Bitmap bitmap = null;
		HttpURLConnection conn;
		URL url = null;
		InputStream is = null;

		try
		{
			url = new URL(path);
			conn = (HttpURLConnection) url.openConnection();
			conn.setDoInput(true);
			conn.connect();
			int fileSize = conn.getContentLength();
			System.out.println("文件" + path + "大小:" + fileSize);
			is = conn.getInputStream();
			System.out.println("从网络加载图片：" + path);
			bitmap = BitmapFactory.decodeStream(is);
			if (bitmap != null)
			{
				/**
				 * 创建一个固定宽高的bitmap对象
				 */
				bitmap = bitmap.createScaledBitmap(bitmap, bitmap.getWidth(), bitmap.getHeight(), true);
			}
		}
		catch (OutOfMemoryError e)
		{
			System.gc();
			Log.i(TAG, e.toString());
			return null;
		}
		catch (Exception e)
		{
			Log.i(TAG, e.toString());
			return null;
		}
		finally
		{
			if (is != null)
			{
				try
				{
					is.close();
				}
				catch (IOException e)
				{
					e.printStackTrace();
					return null;
				}
			}
		}
		return bitmap;
	}

	/**
	 * 从sd卡中读取文件
	 * 
	 * @param url
	 * @return
	 */
	public Bitmap getBitmapFromSD(String url)
	{
		try
		{
			Bitmap bmp = null;
			// 判SD卡中是否存在文件
			String filename = convertUrlToFileName(url);
			String dir = getDirectory(filename);
			File file = new File(dir + "/" + filename);
			if (file.exists())
			{
				removeExpiredCache(dir, filename);
				updateFileTime(dir, filename);
				BitmapFactory.Options opts = new BitmapFactory.Options();
				opts.inJustDecodeBounds = true;
				BitmapFactory.decodeFile(file.getAbsolutePath(), opts);
				opts.inSampleSize = computeSampleSize(opts, -1, 720 * 360);
				opts.inJustDecodeBounds = false;
				try
				{
					bmp = BitmapFactory.decodeFile(file.getAbsolutePath(), opts);
				}
				catch (OutOfMemoryError err)
				{
					return null;
				}
				if (bmp != null)
				{
					return bmp;
				}
			}
		}
		catch (Exception e)
		{
			return null;
		}
		return null;

	}

	private String convertUrlToFileName(String url)
	{
		int lastIndex = url.lastIndexOf('/');
		return url.substring(lastIndex + 1);
	}

	private String getDirectory(String filename)
	{
		return WHOLESALE_CONV;
	}

	private void removeExpiredCache(String dirPath, String filename)
	{

		File file = new File(dirPath, filename);

		if (System.currentTimeMillis() - file.lastModified() > mTimeDiff)
		{

			System.out.println("删除过期文件：" + file.getAbsolutePath());
			file.delete();
		}
	}

	private void updateFileTime(String dir, String fileName)
	{
		File file = new File(dir, fileName);
		long newModifiedTime = System.currentTimeMillis();
		System.out.println("修改文件更新时间：" + file.getAbsolutePath());
		file.setLastModified(newModifiedTime);
	}

	/**
	 * 保存文件至SD卡
	 * 
	 * @param bm
	 * @param url
	 */
	private void saveBmpToSd(Bitmap bm, String url)
	{
		if (bm == null)
		{
			Log.w(TAG, " trying to savenull bitmap");
			return;
		}
		// 判断sdcard上的空间
		if (FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd())
		{
			Log.w(TAG, "Low free space onsd, do not cache");
			removeCache(WHOLESALE_CONV);
			return;
		}
		String filename = convertUrlToFileName(url);
		String dir = getDirectory(filename);
		File file = new File(dir + "/" + filename);
		try
		{
			if (!file.exists())
			{
				file.getParentFile().mkdirs();
			}
			file.createNewFile();
			OutputStream outStream = new FileOutputStream(file);
			if (!url.substring(url.lastIndexOf("/") + 1).toUpperCase().contains("PNG"))
			{
				bm.compress(Bitmap.CompressFormat.JPEG, 100, outStream);
			}
			else
			{
				bm.compress(Bitmap.CompressFormat.PNG, 100, outStream);
			}
			outStream.flush();
			outStream.close();
			Log.i(TAG, "Image saved tosd");

		}
		catch (FileNotFoundException e)
		{
			Log.w(TAG, "FileNotFoundException");
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}

	private int freeSpaceOnSd()
	{
		StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
		double sdFreeMB = ((double) stat.getAvailableBlocks() * (double) stat.getBlockSize()) / 1024 * 1024;
		return (int) sdFreeMB;
	}

	private void removeCache(String dirPath)
	{
		File dir = new File(dirPath);
		File[] files = dir.listFiles();
		if (files == null)
		{
			return;
		}
		int dirSize = 0;
		for (int i = 0; i < files.length; i++)
		{
			if (files[i].getName().contains(WHOLESALE_CONV))
			{
				dirSize += files[i].length();
			}
		}
		if (dirSize > CACHE_SIZE * 1024 * 1024 || FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd())
		{
			int removeFactor = (int) ((0.4 * files.length) + 1);

			Arrays.sort(files, new FileLastModifSort());

			Log.i(TAG, "Clear some expiredcache files ");

			for (int i = 0; i < removeFactor; i++)
			{

				if (files[i].getName().contains(WHOLESALE_CONV))
				{

					files[i].delete();

				}

			}

		}

	}

	/**
	 * 根据文件的最后修改时间进行排序 *
	 */
	class FileLastModifSort implements Comparator<File>
	{
		public int compare(File arg0, File arg1)
		{
			if (arg0.lastModified() > arg1.lastModified())
			{
				return 1;
			}
			else if (arg0.lastModified() == arg1.lastModified())
			{
				return 0;
			}
			else
			{
				return -1;
			}
		}
	}

	public static int computeSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels)
	{
		int initialSize = computeInitialSampleSize(options, minSideLength, maxNumOfPixels);
		int roundedSize;
		if (initialSize <= 8)
		{
			roundedSize = 1;
			while (roundedSize < initialSize)
			{
				roundedSize <<= 1;
			}
		}
		else
		{
			roundedSize = (initialSize + 7) / 8 * 8;
		}
		return roundedSize;
	}

	private static int computeInitialSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels)
	{
		double w = options.outWidth;
		double h = options.outHeight;
		int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));
		int upperBound = (minSideLength == -1) ? 128 : (int) Math.min(Math.floor(w / minSideLength), Math.floor(h / minSideLength));
		if (upperBound < lowerBound)
		{
			return lowerBound;
		}
		if ((maxNumOfPixels == -1) && (minSideLength == -1))
		{
			return 1;
		}
		else if (minSideLength == -1)
		{
			return lowerBound;
		}
		else
		{
			return upperBound;
		}
	}

}
